home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / opml.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  6.8 KB  |  194 lines

  1. # Miro - an RSS based video player application
  2. # Copyright (C) 2005-2007 Participatory Culture Foundation
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  17.  
  18. import os
  19.  
  20. from xml.dom import minidom
  21. from xml.sax import saxutils
  22. from xml.parsers import expat
  23. from datetime import datetime
  24. from StringIO import StringIO
  25.  
  26. import app
  27. import util
  28. import feed
  29. import views
  30. import prefs
  31. import config
  32. import folder
  33. import dialogs
  34. import eventloop
  35.  
  36. from gtcache import gettext as _
  37. from gtcache import ngettext
  38.  
  39. # =============================================================================
  40.  
  41. class Exporter (object):
  42.  
  43.     def __init__(self):
  44.         self.io = StringIO()
  45.         self.currentFolder = None
  46.  
  47.     def exportSubscriptions(self):
  48.         callback = lambda p: self.exportSubscriptionsTo(p)
  49.         title = _("Export OPML File")
  50.         app.delegate.askForSavePathname(title, callback, None, u"miro_subscriptions.opml")
  51.  
  52.     @eventloop.asIdle
  53.     def exportSubscriptionsTo(self, pathname):
  54.         now = datetime.now()
  55.         
  56.         self.io.write(u'<?xml version="1.0" encoding="utf-8" ?>\n')
  57.         self.io.write(u'<!-- OPML generated by Miro v%s on %s -->\n' % (config.get(prefs.APP_VERSION), now.ctime()))
  58.         self.io.write(u'<opml version="2.0">\n')
  59.         self.io.write(u'\t<head>\n')
  60.         self.io.write(u'\t\t<title>%s</title>\n' % os.path.basename(pathname))
  61.         self.io.write(u'\t\t<dateCreated>%s</dateCreated>\n' % now.ctime())
  62.         self.io.write(u'\t\t<docs>http://www.opml.org/spec2</docs>\n')
  63.         self.io.write(u'\t</head>\n')
  64.         self.io.write(u'\t<body>\n')
  65.     
  66.         tabOrder = util.getSingletonDDBObject(views.channelTabOrder)
  67.         for tab in tabOrder.getAllTabs():
  68.             if tab.isChannelFolder():
  69.                 self._openFolderEntry(tab.obj)
  70.             elif tab.isFeed():
  71.                 self._writeFeedEntry(tab.obj)
  72.     
  73.         if self.currentFolder is not None:
  74.             self._closeFolderEntry()
  75.     
  76.         self.io.write(u'\t</body>\n')
  77.         self.io.write(u'</opml>\n')
  78.     
  79.         f = open(pathname, "w")
  80.         f.write(self.io.getvalue().encode('utf-8'))
  81.         f.close()
  82.  
  83.     def _openFolderEntry(self, folder):
  84.         if self.currentFolder is not None:
  85.             self._closeFolderEntry()
  86.         self.currentFolder = folder
  87.         self.io.write(u'\t\t<outline text=%s>\n' % saxutils.quoteattr(folder.getTitle()))
  88.  
  89.     def _closeFolderEntry(self):
  90.         self.io.write(u'\t\t</outline>\n')
  91.  
  92.     def _writeFeedEntry(self, thefeed):
  93.         if (self.currentFolder is not None) and (thefeed.getFolder() is None):
  94.             self._closeFolderEntry()
  95.             self.currentFolder = None
  96.         if self.currentFolder is None:
  97.             spacer = u'\t\t'
  98.         else:
  99.             spacer = u'\t\t\t'
  100.  
  101.         # FIXME - RSSFeedImpl items should be of type "rss", but
  102.         # it's not clear what type other things should be.  We
  103.         # mark them as "mirofeed"--this should get changed if there
  104.         # are issues.
  105.         if isinstance(thefeed.getActualFeed(), feed.RSSFeedImpl):
  106.             feedtype = u'type="rss"'
  107.         else:
  108.             feedtype = u'type="mirofeed"'
  109.  
  110.         self.io.write(u'%s<outline %s text=%s xmlUrl=%s />\n' % (spacer, feedtype, saxutils.quoteattr(thefeed.getTitle()), saxutils.quoteattr(thefeed.getURL())))
  111.  
  112. # =============================================================================
  113.  
  114. class Importer (object):
  115.  
  116.     def __init__(self):
  117.         self.currentFolder = None
  118.         self.ignoredFeeds = 0
  119.         self.importedFeeds = 0
  120.  
  121.     def importSubscriptions(self):
  122.         callback = lambda p: self.importSubscriptionsFrom(p)
  123.         title = _("Import OPML File")
  124.         app.delegate.askForOpenPathname(title, callback, None, 
  125.                 _("OPML Files"), ['opml'])
  126.  
  127.     @eventloop.asIdle
  128.     def importSubscriptionsFrom(self, pathname, showSummary = True):
  129.         f = open(pathname, "r")
  130.         content = f.read()
  131.         f.close()
  132.         
  133.         try:
  134.             dom = minidom.parseString(content)
  135.             root = dom.documentElement
  136.             body = root.getElementsByTagName("body").pop()
  137.             self._walkOutline(body)
  138.             dom.unlink()
  139.             if showSummary:
  140.                 self.showImportSummary()
  141.         except expat.ExpatError:
  142.             self.showXMLError()
  143.  
  144.     def showXMLError(self):
  145.         title = _(u"OPML Import failed")
  146.         message = _(u"The selected OPML file appears to be invalid. Import was interrupted.")
  147.         dialog = dialogs.MessageBoxDialog(title, message)
  148.         dialog.run()
  149.  
  150.     def showImportSummary(self):
  151.         title = _(u"OPML Import summary")
  152.         message = ngettext(u"Successfully imported %d feed.", u"Successfully imported %d feeds.", self.importedFeeds) % self.importedFeeds
  153.         if self.ignoredFeeds > 0:
  154.             message += "\n"
  155.             message += ngettext(u"Skipped %d feed already present.", u"Skipped %d feeds already present.", self.ignoredFeeds) % self.ignoredFeeds
  156.         dialog = dialogs.MessageBoxDialog(title, message)
  157.         dialog.run()
  158.         
  159.     def _walkOutline(self, node):
  160.         try:
  161.             children = node.childNodes
  162.             for child in children:
  163.                 if hasattr(child, 'getAttribute'):
  164.                     if child.hasAttribute("xmlUrl"):
  165.                         self._handleFeedEntry(child)
  166.                     else:
  167.                         self._handlerFolderEntry(child)
  168.             self.currentFolder = None
  169.         except Exception, e:
  170.             print e
  171.             pass
  172.             
  173.     def _handleFeedEntry(self, entry):
  174.         url = entry.getAttribute("xmlUrl")
  175.         f = feed.getFeedByURL(url)
  176.         if f is None:
  177.             f = feed.Feed(url, False)
  178.             title = entry.getAttribute("text")
  179.             if title is not None and title != '':
  180.                 f.setTitle(title)
  181.             if self.currentFolder is not None:
  182.                 f.setFolder(self.currentFolder)
  183.                 f.blink()
  184.             self.importedFeeds += 1
  185.         else:
  186.             self.ignoredFeeds += 1
  187.     
  188.     def _handlerFolderEntry(self, entry):
  189.         title = entry.getAttribute("text")
  190.         self.currentFolder = folder.ChannelFolder(title)
  191.         self._walkOutline(entry)
  192.  
  193. # =============================================================================
  194.